/**
 * Created by Ynlh on 15/10/19.
 */
var keyMap = {
    38 : 0, // Up
    39 : 1, // Right
    40 : 2, // Down
    37 : 3, // Left
    75 : 0, // Vim up
    76 : 1, // Vim right
    74 : 2, // Vim down
    72 : 3, // Vim left
    87 : 0, // W
    68 : 1, // D
    83 : 2, // S
    65 : 3  // A
};

var Game = cc.LayerColor.extend({

    startTiles : 2,

    ctor : function () {
        this._super();

        this.color = cc.color("#faf8ef");
        this.cascadeColor = false;

        this.score = 0;
        this.best = 0;
        this.over = false;
        this.won = false;
        this.keepPlaying = false;

        //var labelTitle = new cc.LabelTTF("2048", "ClearSans-Bold", 80);
        var labelTitle = new cc.LabelBMFont("2048", res.fnt_ClearSans_Bold);
        labelTitle.attr({
            x : 180,
            y : cc.winSize.height - 70,
            scale : 0.85,
            color : cc.color("#776e65")
        });
        this.addChild(labelTitle);

        var scoreBg = new cc.Scale9Sprite(res.bg_tile);
        scoreBg.attr({
            x : 375,
            y : cc.winSize.height - 70,
            width : 120,
            height : 80,
            color : cc.color("#bbada0"),
            cascadeColor : false
        });
        this.addChild(scoreBg);

        //var scoreTitle = new cc.LabelTTF("分 数", "ClearSans-Regular", 20);
        var scoreTitle = new cc.LabelBMFont("当前分数", res.fnt_YaHei_Regular);
        scoreTitle.attr({
            x : 60,
            y : 58,
            scale : 0.6,
            color : cc.color("#faf8ef")
        });
        scoreBg.addChild(scoreTitle);

        //var scoreNum = new cc.LabelTTF("0", "ClearSans-Regular", 30);
        this.scoreNum = new cc.LabelBMFont(this.score.toString(), res.fnt_YaHei_Regular);
        this.scoreNum.attr({
            x : 60,
            y : 28,
            color : cc.color("#ffffff")
        });
        scoreBg.addChild(this.scoreNum);

        var bestBg = new cc.Scale9Sprite(res.bg_tile);
        bestBg.attr({
            x : 505,
            y : cc.winSize.height - 70,
            width : 120,
            height : 80,
            color : cc.color("#bbada0"),
            cascadeColor : false
        });
        this.addChild(bestBg);

        //var bestTitle = new cc.LabelTTF("最 高", "ClearSans-Regular", 20);
        var bestTitle = new cc.LabelBMFont("历史最高", res.fnt_YaHei_Regular);
        bestTitle.attr({
            x : 60,
            y : 58,
            scale : 0.6,
            color : cc.color("#faf8ef")
        });
        bestBg.addChild(bestTitle);

        //var bestNum = new cc.LabelTTF("0", "ClearSans-Regular", 30);
        this.bestNum = new cc.LabelBMFont(this.best.toString(), res.fnt_YaHei_Regular);
        this.bestNum.attr({
            x : 60,
            y : 28,
            color : cc.color("#ffffff")
        });
        bestBg.addChild(this.bestNum);

        //目标合并这些数字以得到方块当前分数历史最高成绩纪录：！

        //var labelTip = new cc.LabelTTF("目标：合并这些数字以得到2048方块！", "Arial", 20);
        var labelTip = new cc.LabelBMFont("目标：合并这些数字以得到2048方块！", res.fnt_YaHei_Regular);
        labelTip.attr({
            anchorX : 0,
            x : 90,
            y : cc.winSize.height - 150,
            scale : 0.7,
            color : cc.color("#776e65")
        });
        this.addChild(labelTip);

        var btnRefresh = new ccui.Button(res.btn_refresh);
        btnRefresh.attr({
            x : 505,
            y : cc.winSize.height - 150
        });
        btnRefresh.addClickEventListener(function () {
            Game.getInstance().grid.empty();
            Game.getInstance().addStartTiles();
        });
        this.addChild(btnRefresh, 10);

        this.grid = new Grid();
        this.addChild(this.grid);

        this.addStartTiles();
    },

    addStartTiles : function () {
        for (var i = 0; i < this.startTiles; i++)
            this.addRandomTile();
    },

    addRandomTile : function () {
        if (this.grid.cellsAvailable()) {
            var value = Math.random() < 0.9 ? 2 : 4;
            var tile = new Tile(this.grid.randomAvailableCell(), value);
            this.grid.addTile(tile);
        }
    },

    updateScore : function (score) {
        this.score = this.score + score;
        this.scoreNum.string = this.score.toString();

        this.updateBest();
    },

    updateBest : function () {
        this.best = this.score;
        this.bestNum.string = this.best.toString();
    },

    //move : function (row, callback, add) {
    //    add = arguments[2] || 0;
    //
    //    var a = Math.abs(0 - add);
    //    var b = Math.abs(1 - add);
    //    var c = Math.abs(2 - add);
    //    var d = Math.abs(3 - add);
    //
    //    if (row[c]) {
    //        if (row[d]) {
    //            if (row[c].value == row[d].value) {
    //                row[d].updateValue(d - c);
    //                row[c].move(d - c, callback, true);
    //            }
    //        } else {
    //            row[d] = row[c];
    //            row[d].move(d - c, callback);
    //        }
    //    }
    //
    //    if (row[b]) {
    //        if (row[d]) {
    //            if (row[c]) {
    //                if (row[b].value == row[c].value) {
    //                    row[c].updateValue(c - b);
    //                    row[b].move(c - b, callback, true);
    //                }
    //            } else {
    //                if (row[b].value == row[d].value) {
    //                    row[d].updateValue(d - b);
    //                    row[b].move(d - b, callback, true);
    //                } else {
    //                    row[c] = row[b];
    //                    row[c].move(c - b, callback);
    //                }
    //            }
    //        } else {
    //            row[d] = row[b];
    //            row[d].move(d - b, callback);
    //        }
    //    }
    //
    //    if (row[a]) {
    //        if (row[d]) {
    //            if (row[c]) {
    //                if (row[b]) {
    //                    if (row[a].value == row[b].value) {
    //                        row[b].updateValue(b - a);
    //                        row[a].move(b - a, callback, true);
    //                    }
    //                } else {
    //                    if (row[a].value == row[c].value) {
    //                        row[c].updateValue(c - a);
    //                        row[a].move(c - a, callback, true);
    //                    } else {
    //                        row[b] = row[a];
    //                        row[b].move(b - a, callback);
    //                    }
    //                }
    //            } else {
    //                if (row[a].value == row[d].value) {
    //                    row[d].updateValue(d - a);
    //                    row[a].move(d - a, callback, true);
    //                } else {
    //                    row[c] = row[a];
    //                    row[c].move(c - a, callback);
    //                }
    //            }
    //        } else {
    //            row[d] = row[a];
    //            row[d].move(d - a, callback);
    //        }
    //    }
    //},

    /**
     * @function
     * @param {Function} callback
     * @param {Number} i  index 位置
     * @param {Boolean} v  isVertical 是否垂直
     * @param {Boolean} [r]  isReverse 是否相反
     */
    _move : function (callback, i, v, r) {
        var a = r ? 3 : 0;
        var b = r ? 2 : 1;
        var c = r ? 1 : 2;
        var d = r ? 0 : 3;

        var isOne = true;
        var isTwo = true;

        var cells = this.grid.cells;

        if (cells[v ? i : c][v ? c : i]) {
            if (cells[v ? i : d][v ? d : i]) {
                if (cells[v ? i : c][v ? c : i].value == cells[v ? i : d][v ? d : i].value) {
                    cells[v ? i : c][v ? c : i].move(d - c, v, callback, true);
                    cells[v ? i : d][v ? d : i].update(d - c);

                    isOne = false;
                }
            } else {
                cells[v ? i : d][v ? d : i] = cells[v ? i : c][v ? c : i];
                cells[v ? i : d][v ? d : i].move(d - c, v, callback);
            }
        }

        if (cells[v ? i : b][v ? b : i]) {
            if (cells[v ? i : d][v ? d : i]) {
                if (cells[v ? i : c][v ? c : i]) {
                    if (cells[v ? i : b][v ? b : i].value == cells[v ? i : c][v ? c : i].value) {
                        cells[v ? i : b][v ? b : i].move(c - b, v, callback, true);
                        cells[v ? i : c][v ? c : i].update(c - b);

                        isTwo = false;
                    }
                } else {
                    if (isOne && cells[v ? i : b][v ? b : i].value == cells[v ? i : d][v ? d : i].value) {
                        cells[v ? i : b][v ? b : i].move(d - b, v, callback, true);
                        cells[v ? i : d][v ? d : i].update(d - b);

                        isOne = false;
                    } else {
                        cells[v ? i : c][v ? c : i] = cells[v ? i : b][v ? b : i];
                        cells[v ? i : c][v ? c : i].move(c - b, v, callback);
                    }
                }
            } else {
                cells[v ? i : d][v ? d : i] = cells[v ? i : b][v ? b : i];
                cells[v ? i : d][v ? d : i].move(d - b, v, callback);
            }
        }

        if (cells[v ? i : a][v ? a : i]) {
            if (cells[v ? i : d][v ? d : i]) {
                if (cells[v ? i : c][v ? c : i]) {
                    if (cells[v ? i : b][v ? b : i]) {
                        if (cells[v ? i : a][v ? a : i].value == cells[v ? i : b][v ? b : i].value) {
                            cells[v ? i : a][v ? a : i].move(b - a, v, callback, true);
                            cells[v ? i : b][v ? b : i].update(b - a);
                        }
                    } else {
                        if (isTwo && cells[v ? i : a][v ? a : i].value == cells[v ? i : c][v ? c : i].value) {
                            cells[v ? i : a][v ? a : i].move(c - a, v, callback, true);
                            cells[v ? i : c][v ? c : i].update(c - a);
                        } else {
                            cells[v ? i : b][v ? b : i] = cells[v ? i : a][v ? a : i];
                            cells[v ? i : b][v ? b : i].move(b - a, v, callback);
                        }
                    }
                } else {
                    if (isOne && cells[v ? i : a][v ? a : i].value == cells[v ? i : d][v ? d : i].value) {
                        cells[v ? i : a][v ? a : i].move(d - a, v, callback, true);
                        cells[v ? i : d][v ? d : i].update(d - a);
                    } else {
                        cells[v ? i : c][v ? c : i] = cells[v ? i : a][v ? a : i];
                        cells[v ? i : c][v ? c : i].move(c - a, v, callback);
                    }
                }
            } else {
                cells[v ? i : d][v ? d : i] = cells[v ? i : a][v ? a : i];
                cells[v ? i : d][v ? d : i].move(d - a, v, callback);
            }
        }
    },

    onMove : function (key) {
        var step = 0;

        function callback(_step) {
            step = _step > step ? _step : step;
        }

        for (var i = 0; i < 4; i++) {
            switch (key) {
                case 0:
                    this._move(callback, i, true);
                    break;
                case 1:
                    this._move(callback, i, false);
                    break;
                case 2:
                    this._move(callback, i, true, true);
                    break;
                case 3:
                    this._move(callback, i, false, true);
                    break;
            }
        }

        if (step > 0) {
            var a1 = cc.delayTime(0.1);
            //var a1 = cc.delayTime(step * speed + 0.01);
            var a2 = cc.callFunc(function () {
                Game.getInstance().addRandomTile();
            });
            var a3 = cc.sequence(a1, a2);
            this.runAction(a3);
        }
    },

    onEnter : function () {
        this._super();

        cc.eventManager.addListener({
            event : cc.EventListener.KEYBOARD,
            onKeyPressed : function (keyCode, event) {
                if (keyMap[keyCode] != undefined)
                    event.getCurrentTarget().onMove(keyMap[keyCode]);
            }
        }, this);

        var moveLength = 10;
        var beganLocation = null;

        cc.eventManager.addListener({
            event : cc.EventListener.TOUCH_ONE_BY_ONE,
            swallowTouches : true,
            onTouchBegan : function (touch, event) {
                var target = event.getCurrentTarget();
                var location = touch.getLocation();

                if (cc.rectContainsPoint(target.getBoundingBox(), location)) {
                    beganLocation = location;
                    return true;
                }

                return false;
            },
            onTouchMoved : function (touch, event) {
            },
            onTouchEnded : function (touch, event) {
                var endLocation = touch.getLocation();
                var dx = endLocation.x - beganLocation.x;
                var dy = endLocation.y - beganLocation.y;
                var absDx = Math.abs(dx);
                var absDy = Math.abs(dy);

                if (Math.max(absDx, absDy) > moveLength)
                    Game.getInstance().onMove(absDx > absDy ? (dx > 0 ? 1 : 3) : (dy > 0 ? 0 : 2));
            }
        }, this.grid);
    },

    onExit : function () {
        this._super();

        cc.eventManager.removeListener(cc.EventListener.KEYBOARD);
        cc.eventManager.removeListener(cc.EventListener.TOUCH_ONE_BY_ONE);
    }
});

Game._instance = null;

Game.getInstance = function () {
    if (Game._instance == null)
        Game._instance = new Game();
    return Game._instance;
};